devtunnel-cli 3.0.12 → 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 CHANGED
@@ -106,7 +106,7 @@ MIT License - see [LICENSE](docs/LICENSE)
106
106
 
107
107
  ---
108
108
 
109
- **Version 3.0.11** | Made with ❤️ for developers worldwide
109
+ **Version 3.0.13** | Made with ❤️ for developers worldwide
110
110
 
111
111
  ---
112
112
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "devtunnel-cli",
3
- "version": "3.0.12",
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",
@@ -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
 
@@ -60,7 +62,57 @@ function safeUnlink(filePath) {
60
62
  }
61
63
  } catch (err) {
62
64
  // Ignore permission errors - file might be locked or in use
63
- // Will be cleaned up later or on next run
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;
64
116
  }
65
117
  }
66
118
 
@@ -220,12 +272,32 @@ async function downloadWithRetry(urls, dest, maxRetries = 3) {
220
272
 
221
273
  if (err.message.includes('Permission denied') || err.message.includes('EPERM') || err.message.includes('EACCES')) {
222
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
+
223
291
  console.log('\n💡 Solutions:');
224
- console.log(' 1. Run terminal as Administrator (Right-click → Run as administrator)');
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
+ }
225
297
  console.log(' 2. Check if antivirus is blocking file writes');
226
298
  console.log(' 3. Check folder permissions for:', path.dirname(dest));
227
299
  console.log(' 4. Try installing manually: https://github.com/cloudflare/cloudflared/releases\n');
228
- throw err; // Don't retry permission errors
300
+ throw err;
229
301
  } else if (err.message.includes('ENOTFOUND') || err.message.includes('ECONNREFUSED')) {
230
302
  console.log(`\n❌ Network error: ${err.message}`);
231
303
  } else if (err.message.includes('timeout')) {
@@ -346,7 +418,12 @@ export async function setupCloudflared() {
346
418
 
347
419
  if (err.message.includes('Permission denied') || err.message.includes('EPERM') || err.message.includes('EACCES')) {
348
420
  console.log('💡 Permission Error Solutions:');
349
- console.log(' 1. Run terminal as Administrator (Right-click → Run as administrator)');
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
+ }
350
427
  console.log(' 2. Check antivirus is not blocking file writes');
351
428
  console.log(' 3. Check folder permissions for:', path.dirname(binaryPath));
352
429
  console.log(' 4. Try installing Cloudflare manually:');
package/src/core/start.js CHANGED
@@ -183,7 +183,7 @@ async function main() {
183
183
  // Show ASCII logo
184
184
  showLogo();
185
185
 
186
- console.log("DevTunnel v3.0.12");
186
+ console.log("DevTunnel v3.0.13");
187
187
  console.log("Share your local dev servers worldwide");
188
188
  console.log("");
189
189
  console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");