UNPKG

coolify-deploy-logs-cli

Version:
307 lines (250 loc) • 12.7 kB
#!/usr/bin/env node /** * Coolify Tools - Working Version with proper login handling */ const https = require('https'); const { URL } = require('url'); class CoolifyDeployWorking { constructor(baseURL = null, githubRepo = null, domain = null) { // Support command line arguments or environment variables this.baseURL = baseURL || process.env.COOLIFY_URL || process.argv[2] || 'https://coolify.247420.xyz'; // Ensure URL has proper protocol if (this.baseURL && !this.baseURL.startsWith('http://') && !this.baseURL.startsWith('https://')) { this.baseURL = 'https://' + this.baseURL; } this.githubRepo = githubRepo || process.env.GITHUB_REPO || process.argv[3] || 'https://github.com/AnEntrypoint/nixpacks-test-app.git'; this.domain = domain || process.env.DOMAIN || process.argv[4] || 'schwepe.247420.xyz'; this.cookies = ''; this.csrfToken = null; this.projectId = null; this.environmentId = null; this.applicationId = null; console.log('šŸš€ Coolify Deploy Tool'); console.log('šŸ“” Target URL: ' + this.baseURL); console.log('šŸ“¦ Repository: ' + this.githubRepo); console.log('🌐 Domain: ' + this.domain); } async request(url, options = {}, followRedirects = true) { return new Promise((resolve, reject) => { const makeRequest = (requestUrl, redirectCount = 0) => { if (redirectCount > 5) { reject(new Error('Too many redirects')); return; } const urlObj = new URL(requestUrl); const requestOptions = { hostname: urlObj.hostname, port: urlObj.port || (urlObj.protocol === 'https:' ? 443 : 80), path: urlObj.pathname + urlObj.search, method: options.method || 'GET', headers: { 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', 'Accept-Language': 'en-US,en;q=0.5', 'Accept-Encoding': 'gzip, deflate, br', 'Connection': 'keep-alive', 'Upgrade-Insecure-Requests': '1', ...options.headers } }; if (this.cookies) { requestOptions.headers['Cookie'] = this.cookies; } if (options.data) { const data = typeof options.data === 'string' ? options.data : JSON.stringify(options.data); requestOptions.headers['Content-Type'] = requestOptions.headers['Content-Type'] || 'application/json'; requestOptions.headers['Content-Length'] = Buffer.byteLength(data); } const req = https.request(requestOptions, (res) => { let rawData = ''; res.on('data', (chunk) => { rawData += chunk; }); res.on('end', () => { // Handle cookies if (res.headers['set-cookie']) { this.cookies = res.headers['set-cookie'].map(cookie => cookie.split(';')[0]).join('; '); } // Extract CSRF token if present if (rawData.includes('name="_token"')) { const csrfMatch = rawData.match(/name="_token"[^>]+value="([^"]+)"/); if (csrfMatch) { this.csrfToken = csrfMatch[1]; } } // Handle redirects if (followRedirects && (res.statusCode === 302 || res.statusCode === 301 || res.statusCode === 303)) { if (res.headers.location) { const redirectUrl = res.headers.location.startsWith('http') ? res.headers.location : this.baseURL + res.headers.location; console.log('šŸ”„ Following redirect to:', redirectUrl); return makeRequest(redirectUrl, redirectCount + 1); } } resolve({ status: res.statusCode, headers: res.headers, raw: rawData }); }); }); req.on('error', (err) => { reject(err); }); if (options.data) { const data = typeof options.data === 'string' ? options.data : JSON.stringify(options.data); req.write(data); } req.end(); }; makeRequest(url); }); } async login() { console.log('\nšŸ” Logging in...'); try { // Get login page first console.log('šŸ“ Getting login page...'); const loginPage = await this.request(this.baseURL + '/login'); if (!this.csrfToken) { throw new Error('Could not find CSRF token on login page'); } console.log('šŸ”‘ Found CSRF token:', this.csrfToken.substring(0, 20) + '...'); // Submit login console.log('šŸ“ Submitting login form...'); const loginResponse = await this.request(this.baseURL + '/login', { method: 'POST', data: 'email=admin%40247420.xyz&password=123%2Cslam123%2Cslam&_token=' + this.csrfToken, headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Referer': this.baseURL + '/login' } }); console.log('šŸ” Login response status:', loginResponse.status); if (loginResponse.status === 302 || loginResponse.status === 200) { console.log('āœ… Login successful'); // After successful login, try to access the main page const mainResponse = await this.request(this.baseURL); console.log('šŸ“„ Main page status:', mainResponse.status); return true; } else { throw new Error('Login failed with status: ' + loginResponse.status); } } catch (error) { console.error('āŒ Login error:', error.message); throw error; } } async findResources() { console.log('\nšŸ” Looking for existing resources...'); try { // Try different endpoints to find projects const endpoints = [ this.baseURL, this.baseURL + '/dashboard', this.baseURL + '/projects', this.baseURL + '/resources' ]; for (const endpoint of endpoints) { console.log('šŸ” Checking endpoint:', endpoint.replace(this.baseURL, '')); try { const response = await this.request(endpoint); // Look for the specific domain in the response if (response.raw.includes(this.domain)) { console.log('āœ… Found existing resource for domain:', this.domain); // Extract project/environment info if possible const projectMatch = response.raw.match(/project\/([a-z0-9]{24})/); if (projectMatch) { this.projectId = projectMatch[1]; console.log('šŸ“‹ Project ID:', this.projectId); } const envMatch = response.raw.match(/environment\/([a-z0-9]{24})/); if (envMatch) { this.environmentId = envMatch[1]; console.log('šŸŒ Environment ID:', this.environmentId); } return true; } // Look for any project patterns const projectMatches = response.raw.match(/project\/([a-z0-9]{24})/g); if (projectMatches && projectMatches.length > 0) { console.log('šŸ“‹ Found projects:', projectMatches.length); this.projectId = projectMatches[0].replace('project/', ''); console.log('šŸ“‹ Using first project ID:', this.projectId); // Now try to get environment from the project page const projectResponse = await this.request(this.baseURL + '/project/' + this.projectId); const envMatches = projectResponse.raw.match(/environment\/([a-z0-9]{24})/g); if (envMatches && envMatches.length > 0) { this.environmentId = envMatches[0].replace('environment/', ''); console.log('šŸŒ Found environment ID:', this.environmentId); } return false; // Found project but not the specific domain } } catch (error) { console.log(' āŒ Error accessing endpoint:', error.message); } } console.log('ā„¹ļø No existing resources found'); return false; } catch (error) { console.error('āŒ Resource search error:', error.message); return false; } } async deploy() { try { console.log('\nšŸš€ Starting deployment process...'); // Step 1: Login await this.login(); // Step 2: Look for existing resources const resourceExists = await this.findResources(); if (resourceExists) { console.log('\nāœ… Resource already exists for ' + this.domain); if (this.projectId) { console.log('🌐 Manage at: ' + this.baseURL + '/project/' + this.projectId); } return; } console.log('\nšŸ“ Deployment configuration:'); console.log(' Coolify URL: ' + this.baseURL); if (this.projectId) { console.log(' Project ID: ' + this.projectId); } if (this.environmentId) { console.log(' Environment ID: ' + this.environmentId); } console.log(' Repository: ' + this.githubRepo); console.log(' Domain: ' + this.domain); if (this.projectId) { console.log('\n🌐 Manage at: ' + this.baseURL + '/project/' + this.projectId); } else { console.log('\nāš ļø Could not find project - may need manual setup'); } } catch (error) { console.error('\nāŒ Error:', error.message); throw error; } } } // Main execution if (require.main === module) { const baseURL = process.argv[2] || null; const githubRepo = process.argv[3] || null; const domain = process.argv[4] || null; const cli = new CoolifyDeployWorking(baseURL, githubRepo, domain); cli.deploy().catch(err => { console.error('Fatal:', err); process.exit(1); }); } module.exports = CoolifyDeployWorking;