UNPKG

instatunnel

Version:

Expose your localhost to the internet instantly - the ngrok alternative that's 40% cheaper with superior UX

237 lines (200 loc) â€ĸ 7.85 kB
#!/usr/bin/env node const fs = require('fs'); const path = require('path'); const https = require('https'); const os = require('os'); const { execSync } = require('child_process'); const BINARY_NAME = 'instatunnel'; const PRIMARY_URL = 'https://api.instatunnel.my/releases'; const FALLBACK_URL = 'https://github.com/instatunnel/cli/releases/latest/download'; // Colors for console output const colors = { reset: '\x1b[0m', red: '\x1b[31m', green: '\x1b[32m', yellow: '\x1b[33m', blue: '\x1b[34m', cyan: '\x1b[36m' }; function log(message, color = 'reset') { console.log(`${colors[color]}${message}${colors.reset}`); } function detectPlatform() { const platform = os.platform(); const arch = os.arch(); // Map to our actual binary names in the bin/ directory switch (platform) { case 'linux': if (arch === 'arm64') { return 'instatunnel-linux-arm64'; } return 'instatunnel-linux'; case 'darwin': if (arch === 'arm64') { return 'instatunnel-macos-arm64'; } return 'instatunnel-macos'; case 'win32': return 'instatunnel-windows.exe'; default: // Fallback to linux binary for other Unix-like systems return 'instatunnel-linux'; } } function downloadFile(url, outputPath) { return new Promise((resolve, reject) => { const file = fs.createWriteStream(outputPath); https.get(url, (response) => { // Handle redirects if (response.statusCode >= 300 && response.statusCode < 400 && response.headers.location) { file.close(); fs.unlinkSync(outputPath); return downloadFile(response.headers.location, outputPath).then(resolve).catch(reject); } if (response.statusCode !== 200) { file.close(); fs.unlinkSync(outputPath); reject(new Error(`HTTP ${response.statusCode}: ${response.statusMessage}`)); return; } response.pipe(file); file.on('finish', () => { file.close(resolve); }); file.on('error', (err) => { file.close(); fs.unlinkSync(outputPath); reject(err); }); }).on('error', (err) => { reject(err); }); }); } async function setupBinary() { const binaryName = detectPlatform(); const binDir = path.join(__dirname, 'bin'); const isWindows = os.platform() === 'win32'; const outputPath = path.join(binDir, isWindows ? 'instatunnel.exe' : 'instatunnel'); const sourcePath = path.join(binDir, binaryName); log('🚀 Installing InstaTunnel CLI...', 'blue'); log(`📋 Platform: ${os.platform()}-${os.arch()}`, 'cyan'); log(`đŸŽ¯ Using binary: ${binaryName}`, 'cyan'); // Check if the platform-specific binary exists if (!fs.existsSync(sourcePath)) { throw new Error(`Binary for your platform (${binaryName}) not found. Supported platforms: linux, macOS, Windows (x64/arm64)`); } // Copy the platform-specific binary to the standard name fs.copyFileSync(sourcePath, outputPath); // Make executable on Unix systems if (!isWindows) { fs.chmodSync(outputPath, 0o755); } // Create 'it' alias const itPath = path.join(binDir, isWindows ? 'it.exe' : 'it'); fs.copyFileSync(outputPath, itPath); log('✅ InstaTunnel CLI installed successfully!', 'green'); log('', 'reset'); log('🚀 Quick Start:', 'cyan'); log(' instatunnel 3000 # Expose port 3000 instantly (no setup needed!)', 'reset'); log(' it 3000 # Short alias for the same command', 'reset'); log('', 'reset'); log('💡 More examples:', 'cyan'); log(' instatunnel # Auto-detect common ports (3000, 8000, 8080)', 'reset'); log(' instatunnel 8080 --name myapp', 'reset'); log(' instatunnel --help # See all options', 'reset'); log('', 'reset'); log('🌟 Key Benefits:', 'yellow'); log(' ✓ No signup required - works instantly', 'green'); log(' ✓ 24+ hour sessions (vs ngrok\'s 2 hours)', 'green'); log(' ✓ Custom subdomains included free', 'green'); log(' ✓ 40% cheaper than ngrok', 'green'); log('', 'reset'); log('📚 Documentation: https://docs.instatunnel.my', 'yellow'); // Test installation - skip version test to avoid hanging try { // Just verify the file exists and has content const stats = fs.statSync(outputPath); if (stats.size > 1000000) { // Binary should be at least 1MB log(`🔧 Installation verified! Binary size: ${Math.round(stats.size / 1024 / 1024)}MB`, 'green'); } else { log('âš ī¸ Binary seems too small, but installation completed', 'yellow'); } } catch (testError) { log('â„šī¸ Installation complete - restart terminal if command not found', 'yellow'); } } // Create uninstall script function createUninstallScript() { const uninstallPath = path.join(__dirname, 'uninstall.js'); const uninstallScript = `#!/usr/bin/env node const fs = require('fs'); const path = require('path'); function cleanup() { const binDir = path.join(__dirname, 'bin'); try { if (fs.existsSync(binDir)) { fs.rmSync(binDir, { recursive: true, force: true }); } console.log('✅ InstaTunnel CLI uninstalled successfully!'); } catch (error) { console.warn('âš ī¸ Some cleanup may be incomplete:', error.message); } } if (require.main === module) { cleanup(); } module.exports = { cleanup }; `; fs.writeFileSync(uninstallPath, uninstallScript); } // Create test script function createTestScript() { const testPath = path.join(__dirname, 'test.js'); const testScript = `#!/usr/bin/env node const { execSync } = require('child_process'); const path = require('path'); const os = require('os'); function test() { const binDir = path.join(__dirname, 'bin'); const isWindows = os.platform() === 'win32'; const instatunnelPath = path.join(binDir, isWindows ? 'instatunnel.exe' : 'instatunnel'); const itPath = path.join(binDir, isWindows ? 'it.exe' : 'it'); try { // Test main command const helpOutput = execSync(\`"\${instatunnelPath}" --help\`, { encoding: 'utf8', timeout: 5000 }); console.log('✅ instatunnel command works'); // Test alias const itHelpOutput = execSync(\`"\${itPath}" --help\`, { encoding: 'utf8', timeout: 5000 }); console.log('✅ it alias works'); console.log('✅ All tests passed!'); return true; } catch (error) { console.error('❌ Test failed:', error.message); return false; } } if (require.main === module) { const success = test(); process.exit(success ? 0 : 1); } module.exports = { test }; `; fs.writeFileSync(testPath, testScript); } if (require.main === module) { setupBinary() .then(() => { createUninstallScript(); createTestScript(); }) .catch((err) => { log(`❌ Installation failed: ${err.message}`, 'red'); log('', 'reset'); log('🔧 Troubleshooting:', 'yellow'); log(' â€ĸ Your platform may not be supported yet', 'reset'); log(' â€ĸ Try running: npm install -g instatunnel --verbose', 'reset'); log(' â€ĸ Report issues: https://github.com/instatunnel/cli/issues', 'reset'); process.exit(1); }); }