UNPKG

@tomei/finance

Version:

NestJS package for finance module

301 lines (253 loc) â€ĸ 9.35 kB
#!/usr/bin/env node const { execSync, spawn } = require('child_process'); const fs = require('fs'); const path = require('path'); const os = require('os'); /** * Post-install script for @tomei/finance package * Ensures Puppeteer and Chrome are properly configured for PDF generation * Supports Linux, Windows, and macOS environments */ console.log('🔧 Setting up @tomei/finance package...'); async function setupPuppeteer() { try { const platform = os.platform(); console.log(`📱 Detected platform: ${platform}`); // Check if we're in a CI environment const isCI = process.env.CI === 'true' || process.env.GITHUB_ACTIONS === 'true' || process.env.GITLAB_CI === 'true'; if (isCI) { console.log('🤖 CI environment detected. Skipping interactive Chrome setup.'); console.log('â„šī¸ Chrome will be installed on first PDF generation attempt.'); return; } console.log('đŸ“Ļ Checking Puppeteer Chrome installation...'); // Determine appropriate cache directory based on platform const cacheDir = getCacheDirectory(platform); console.log(` Cache directory: ${cacheDir}`); // Check if Chrome is already installed const chromeExists = await checkChromeInstallation(cacheDir, platform); if (chromeExists) { console.log('✅ Chrome is already installed and ready for PDF generation'); return; } console.log('đŸ“Ĩ Installing Chrome browser for PDF generation...'); // Install system dependencies first (Linux only, and only if we have permissions) if (platform === 'linux') { await installLinuxDependencies(); } // Install Chrome await installChrome(cacheDir, platform); console.log('✅ Puppeteer Chrome setup completed successfully!'); } catch (error) { console.error('âš ī¸ Warning: Puppeteer setup encountered issues:', error.message); console.log(''); console.log('📖 Manual setup instructions:'); console.log(' 1. Run: npx puppeteer browsers install chrome'); if (os.platform() === 'linux') { console.log(' 2. Install dependencies: sudo apt-get install -y libxfixes3 libnss3 libatk-bridge2.0-0t64'); } console.log(' 3. Set environment: export PUPPETEER_CACHE_DIR=' + getCacheDirectory(os.platform())); console.log(''); console.log('📄 PDF generation may not work until Chrome is properly installed.'); } } function getCacheDirectory(platform) { const userId = process.getuid ? process.getuid() : null; const isRoot = userId === 0; switch (platform) { case 'win32': return process.env.PUPPETEER_CACHE_DIR || path.join(process.env.USERPROFILE || process.env.HOME || os.tmpdir(), '.cache', 'puppeteer'); case 'darwin': return process.env.PUPPETEER_CACHE_DIR || path.join(process.env.HOME || os.tmpdir(), '.cache', 'puppeteer'); case 'linux': default: if (isRoot) { return process.env.PUPPETEER_CACHE_DIR || '/root/.cache/puppeteer'; } else { return process.env.PUPPETEER_CACHE_DIR || path.join(process.env.HOME || os.tmpdir(), '.cache', 'puppeteer'); } } } async function checkChromeInstallation(cacheDir, platform) { try { // Check if cache directory exists if (!fs.existsSync(cacheDir)) { return false; } // Look for Chrome executable based on platform let chromePaths = []; if (platform === 'win32') { // Windows Chrome paths chromePaths = [ path.join(cacheDir, '**/chrome.exe'), 'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe', 'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe' ]; } else if (platform === 'darwin') { // macOS Chrome paths chromePaths = [ path.join(cacheDir, '**/chrome'), '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome' ]; } else { // Linux Chrome paths chromePaths = [ path.join(cacheDir, '**/chrome'), '/usr/bin/google-chrome', '/usr/bin/google-chrome-stable', '/usr/bin/chromium-browser' ]; } // Check each possible path for (const chromePath of chromePaths) { try { if (chromePath.includes('**')) { // Use find command for glob patterns const findCommand = platform === 'win32' ? `dir "${cacheDir}" /s /b | findstr chrome.exe` : `find "${cacheDir}" -name "chrome" -type f -executable 2>/dev/null | head -1`; const result = execSync(findCommand, { encoding: 'utf8' }).trim(); if (result && fs.existsSync(result.split('\n')[0])) { const foundPath = result.split('\n')[0]; console.log(` Found Chrome at: ${foundPath}`); // Test if Chrome can start (with timeout) if (await testChromeStartup(foundPath, platform)) { return true; } } } else { // Direct path check if (fs.existsSync(chromePath)) { console.log(` Found Chrome at: ${chromePath}`); // Test if Chrome can start if (await testChromeStartup(chromePath, platform)) { return true; } } } } catch (e) { // Continue checking other paths } } return false; } catch (error) { return false; } } async function testChromeStartup(chromePath, platform) { try { const versionArg = platform === 'win32' ? '--version' : '--version --no-sandbox'; execSync(`"${chromePath}" ${versionArg}`, { stdio: 'pipe', timeout: 10000 }); console.log(` ✅ Chrome startup test successful`); return true; } catch (e) { console.log(` âš ī¸ Chrome found but startup test failed`); return false; } } async function installLinuxDependencies() { try { const userId = process.getuid ? process.getuid() : null; const isRoot = userId === 0; if (!isRoot) { console.log(' â„šī¸ Skipping system dependencies (not running as root)'); console.log(' 💡 If you encounter Chrome issues, run: sudo apt-get install -y libxfixes3 libnss3 libatk-bridge2.0-0t64'); return; } console.log('đŸ“Ļ Installing Linux system dependencies...'); // Check if apt-get is available try { execSync('which apt-get', { stdio: 'pipe' }); } catch (e) { console.log(' â„šī¸ apt-get not found, skipping system dependencies'); return; } // Install Chrome dependencies (with error handling for different Ubuntu versions) const dependencies = [ 'libxfixes3', 'libnss3', 'ca-certificates', 'fonts-liberation', 'xdg-utils' ]; // Try modern Ubuntu packages first, fallback to older ones const modernDeps = [ 'libatk-bridge2.0-0t64', 'libasound2t64', 'libatspi2.0-0t64', 'libgtk-3-0t64' ]; const fallbackDeps = [ 'libatk-bridge2.0-0', 'libasound2', 'libatspi2.0-0', 'libgtk-3-0' ]; try { // Try modern packages first execSync(`apt-get update -qq && apt-get install -y ${dependencies.concat(modernDeps).join(' ')}`, { stdio: 'pipe', timeout: 120000 }); console.log(' ✅ Modern system dependencies installed'); } catch (e) { try { // Fallback to older packages execSync(`apt-get install -y ${dependencies.concat(fallbackDeps).join(' ')}`, { stdio: 'pipe', timeout: 120000 }); console.log(' ✅ Fallback system dependencies installed'); } catch (e2) { console.log(' âš ī¸ Could not install some system dependencies'); } } } catch (error) { console.log(' âš ī¸ Could not install system dependencies:', error.message); } } async function installChrome(cacheDir, platform) { try { // Create cache directory fs.mkdirSync(cacheDir, { recursive: true }); // Set environment for installation const installEnv = { ...process.env, PUPPETEER_CACHE_DIR: cacheDir }; // Set HOME appropriately for different platforms if (platform === 'linux') { const userId = process.getuid ? process.getuid() : null; const isRoot = userId === 0; installEnv.HOME = isRoot ? '/root' : process.env.HOME; } console.log(' Installing Chrome browser...'); // Install Chrome using Puppeteer with longer timeout execSync('npx puppeteer browsers install chrome', { stdio: 'pipe', env: installEnv, timeout: 300000 // 5 minutes timeout }); // Verify installation const chromeExists = await checkChromeInstallation(cacheDir, platform); if (!chromeExists) { throw new Error('Chrome installation verification failed'); } console.log(' ✅ Chrome browser installed successfully'); } catch (error) { throw new Error(`Chrome installation failed: ${error.message}`); } } // Run setup setupPuppeteer().then(() => { console.log('🎉 @tomei/finance package setup complete!'); }).catch((error) => { console.error('❌ Setup failed:', error.message); process.exit(0); // Don't fail the npm install });